package com.python.pydev.analysis.system_info_builder;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.python.pydev.core.IInterpreterManager;
import org.python.pydev.core.ModulesKey;
import org.python.pydev.core.docutils.StringUtils;
import org.python.pydev.core.log.Log;
import org.python.pydev.editor.codecompletion.revisited.ModulesFoundStructure;
import org.python.pydev.editor.codecompletion.revisited.PyPublicTreeMap;
import org.python.pydev.editor.codecompletion.revisited.PythonPathHelper;
import org.python.pydev.editor.codecompletion.revisited.SystemModulesManager;
import org.python.pydev.logging.DebugSettings;
import org.python.pydev.ui.pythonpathconf.IInterpreterInfoBuilder;
import org.python.pydev.ui.pythonpathconf.InterpreterInfo;
import com.aptana.shared_core.structure.Tuple;
import com.python.pydev.analysis.additionalinfo.AbstractAdditionalDependencyInfo;
import com.python.pydev.analysis.additionalinfo.AdditionalSystemInterpreterInfo;
/**
* @author fabioz
*/
public class InterpreterInfoBuilder implements IInterpreterInfoBuilder {
static class InterpreterBuilderJob extends Job {
public InterpreterBuilderJob() {
super("InterpreterBuilderJob");
this.setPriority(Job.BUILD);
}
private volatile Set<InterpreterInfoBuilder> buildersToCheck = new HashSet<InterpreterInfoBuilder>();
@Override
protected IStatus run(IProgressMonitor monitor) {
if (DebugSettings.DEBUG_INTERPRETER_AUTO_UPDATE) {
Log.toLogFile(this, "--- Start run");
}
Set<InterpreterInfoBuilder> builders = buildersToCheck;
buildersToCheck = new HashSet<InterpreterInfoBuilder>();
for (InterpreterInfoBuilder builder : builders) {
IStatus ret = checkEarlyReturn(monitor, builder);
if (ret != null) {
continue;
}
PythonPathHelper pythonPathHelper = new PythonPathHelper();
pythonPathHelper.setPythonPath(builder.info.libs);
ModulesFoundStructure modulesFound = pythonPathHelper.getModulesFoundStructure(monitor);
ret = checkEarlyReturn(monitor, builder);
if (ret != null) {
continue;
}
SystemModulesManager modulesManager = (SystemModulesManager) builder.info.getModulesManager();
PyPublicTreeMap<ModulesKey, ModulesKey> keysFound = modulesManager.buildKeysFromModulesFound(monitor,
modulesFound);
if (DebugSettings.DEBUG_INTERPRETER_AUTO_UPDATE) {
Log.toLogFile(this, com.aptana.shared_core.string.StringUtils.format("Found: %s modules", keysFound.size()));
}
ret = checkEarlyReturn(monitor, builder);
if (ret != null) {
continue;
}
Tuple<List<ModulesKey>, List<ModulesKey>> diffModules = modulesManager.diffModules(keysFound);
if (diffModules.o1.size() > 0 || diffModules.o2.size() > 0) {
if (DebugSettings.DEBUG_INTERPRETER_AUTO_UPDATE) {
Log.toLogFile(this, com.aptana.shared_core.string.StringUtils.format("Diff modules. Added: %s Removed: %s", diffModules.o1,
diffModules.o2));
}
//Update the modules manager itself (just pass all the keys as that should be fast)
modulesManager.updateKeysAndSave(keysFound);
//Now, the additional info can be slower, so, let's work only on the deltas...
IInterpreterManager manager = builder.info.getModulesManager().getInterpreterManager();
try {
AbstractAdditionalDependencyInfo additionalSystemInfo = AdditionalSystemInterpreterInfo
.getAdditionalSystemInfo(manager, builder.info.getExecutableOrJar());
additionalSystemInfo.updateKeysIfNeededAndSave(keysFound);
} catch (Exception e) {
Log.log(e);
}
}
}
if (DebugSettings.DEBUG_INTERPRETER_AUTO_UPDATE) {
Log.toLogFile(this, "--- End Run");
}
return Status.OK_STATUS;
}
public IStatus checkEarlyReturn(IProgressMonitor monitor, InterpreterInfoBuilder builder) {
if (builder.isDisposed()) {
if (DebugSettings.DEBUG_INTERPRETER_AUTO_UPDATE) {
Log.toLogFile(this, "Disposed");
}
return Status.OK_STATUS;
}
if (monitor.isCanceled()) {
if (DebugSettings.DEBUG_INTERPRETER_AUTO_UPDATE) {
Log.toLogFile(this, "Cancelled");
}
return Status.OK_STATUS;
}
if (!builder.info.getLoadFinished()) {
if (DebugSettings.DEBUG_INTERPRETER_AUTO_UPDATE) {
Log.toLogFile(this, "Load not finished (rescheduling)");
}
buildersToCheck.add(builder);
builderJob.schedule(20 * 1000); //Check again in 20 seconds
return Status.OK_STATUS;
}
return null;
}
}
private InterpreterInfo info;
private boolean disposed;
private static final InterpreterBuilderJob builderJob = new InterpreterBuilderJob();
boolean isDisposed() {
return this.disposed;
}
public void dispose() {
disposed = true;
}
public void setInfo(InterpreterInfo info) {
setInfo(info, 20 * 1000); //Default: check 20 seconds after starting up...
}
public void setInfo(InterpreterInfo info, int schedule) {
this.info = info;
builderJob.buildersToCheck.add(this);
builderJob.schedule(schedule);
}
}